TerraformでDB接続情報を既存のパラメータストアから参照してRDSを作成してみる
こんにちは!最近Terraformをいじり始めたAWS事業本部の平木です。
今回は、Terraformを使ってSystemManagerのパラメータストアに保管された、
マスターユーザ名とマスターパスワードを参照して、RDSを作成してみました!
構成
踏み台EC2を用意し、セッションマネージャー経由でEC2へ接続からのRDS(MySQL)へ接続する一般的な構成です。
RDSは、SystemManagerのパラメータストアに保管されているパラメータを参照し、設定されます。
リージョンは東京リージョンを指定しています。
手順
SystemManagerのパラメータストアにパラメータを設定する
下記コマンドを実行し、パラメータストアへパラメータを設定します。
--value
の後に任意のユーザ名とパスワードを代入してください。
aws ssm put-parameter \ --name "/rds/mysql/username" \ --description "rds username" \ --value "xxxxx" \ --type String aws ssm put-parameter \ --name "/rds/mysql/password" \ --description "rds password" \ --value "xxxxxxxxxxxx" \ --type SecureString
下記コマンドで設定を確認できます。
aws ssm get-parameters \ --names "/rds/mysql/username" \ --query Parameters[].Value \ --output text aws ssm get-parameters \ --names "/rds/mysql/password" \ --with-decryption \ --query Parameters[].Value \ --output text
TerraformでAWS環境へデプロイ
下記コードを使用し、TerraformでAWSリソースを構築します。
GitHubへもソースコードを公開しておりますので必要に応じてご活用ください。
コードを展開する
terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 4.23.0" } } } provider "aws" { region = "ap-northeast-1" } data "aws_caller_identity" "current" {} locals { account_id = data.aws_caller_identity.current.account_id } data "aws_ssm_parameter" "rds_username" { name = "/rds/mysql/username" } data "aws_ssm_parameter" "rds_password" { name = "/rds/mysql/password" with_decryption = true } data aws_ssm_parameter amzn2_ami { name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" } # VPCを作成 resource "aws_vpc" "my_vpc" { cidr_block = "10.0.0.0/16" enable_dns_hostnames = true tags = { Name = "my-vpc" } } # パブリックサブネットを作成 resource "aws_subnet" "my_subnet1" { vpc_id = aws_vpc.my_vpc.id cidr_block = "10.0.1.0/24" availability_zone = "ap-northeast-1a" tags = { Name = "my-pub-subnet1" } } # プライベートサブネットを作成 resource "aws_subnet" "my_subnet2" { vpc_id = aws_vpc.my_vpc.id cidr_block = "10.0.2.0/24" availability_zone = "ap-northeast-1c" tags = { Name = "my-pri-subnet2" } } # インターネットゲートウェイを作成 resource "aws_internet_gateway" "my_igw" { vpc_id = aws_vpc.my_vpc.id tags = { Name = "my-igw" } } # パブリックサブネットにルートテーブルを作成 resource "aws_route_table" "public_rt" { vpc_id = aws_vpc.my_vpc.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.my_igw.id } tags = { Name = "public-route-table" } } # パブリックサブネットにルートテーブルを関連付ける resource "aws_route_table_association" "public_rta" { subnet_id = aws_subnet.my_subnet1.id route_table_id = aws_route_table.public_rt.id } # プライベートサブネットにルートテーブルを作成 resource "aws_route_table" "private_rt" { vpc_id = aws_vpc.my_vpc.id tags = { Name = "private-route-table" } } # プライベートサブネットにNATゲートウェイを経由するルートテーブルを関連付ける resource "aws_route" "private_route" { route_table_id = aws_route_table.private_rt.id destination_cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.my_nat_gateway.id } resource "aws_route_table_association" "private_rta" { subnet_id = aws_subnet.my_subnet2.id route_table_id = aws_route_table.private_rt.id } # NATゲートウェイを作成 resource "aws_nat_gateway" "my_nat_gateway" { allocation_id = aws_eip.my_eip.id subnet_id = aws_subnet.my_subnet1.id tags = { Name = "my-nat-gateway" } } # Elastic IPを作成 resource "aws_eip" "my_eip" { vpc = true tags = { Name = "my-eip" } } # IAMロール作成 resource "aws_iam_role" "ssm" { name = "ssm-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } Action = "sts:AssumeRole" } ] }) tags = { Name = "ssm-role" } } resource "aws_iam_role_policy_attachment" "ssm" { policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" role = aws_iam_role.ssm.name } # IAMポリシー作成 resource "aws_iam_policy" "ssm-param-access" { name = "ssm-access-policy" policy = jsonencode({ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ssm:DescribeParameters" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ssm:GetParameters" ], "Resource": "arn:aws:ssm:ap-northeast-1:${local.account_id}:parameter/rds/mysql/*" } ] }) tags = { Name = "ssm-access-policy" } } resource "aws_iam_role_policy_attachment" "ssm-param-access" { policy_arn = aws_iam_policy.ssm-param-access.arn role = aws_iam_role.ssm.name } # 踏み台用のEC2をパブリックサブネットに作成 resource "aws_instance" "bastion" { ami = data.aws_ssm_parameter.amzn2_ami.value instance_type = "t2.micro" subnet_id = aws_subnet.my_subnet1.id vpc_security_group_ids = [aws_security_group.bastion_sg.id] iam_instance_profile = aws_iam_instance_profile.ssm.name associate_public_ip_address = true user_data = <<-EOF #!/bin/bash yum update -y yum install -y mysql yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm systemctl enable amazon-ssm-agent systemctl start amazon-ssm-agent EOF tags = { Name = "bastion" } } # インスタンスプロファイルを定義 resource "aws_iam_instance_profile" "ssm" { name = "ssm-instance-profile" role = aws_iam_role.ssm.name } # 踏み台用セキュリティグループを作成 resource "aws_security_group" "bastion_sg" { name_prefix = "bastion-sg-" vpc_id = aws_vpc.my_vpc.id ingress { from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "bastion-sg" } } # データベースセキュリティグループを作成 resource "aws_security_group" "db_sg" { name_prefix = "db-sg-" vpc_id = aws_vpc.my_vpc.id ingress { from_port = 3306 to_port = 3306 protocol = "tcp" security_groups = [ aws_security_group.bastion_sg.id, ] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "db" } } # サブネットグループの作成 resource "aws_db_subnet_group" "rds_subnet_group" { name = "rds_subnet_group" subnet_ids = [aws_subnet.my_subnet1.id, aws_subnet.my_subnet2.id] } # RDS MySQLを作成 resource "aws_db_instance" "rds_instance" { identifier = "myrds" db_name = "myrdsinstance" engine = "mysql" engine_version = "5.7" instance_class = "db.t2.micro" username = data.aws_ssm_parameter.rds_username.value password = data.aws_ssm_parameter.rds_password.value allocated_storage = 10 storage_type = "gp2" backup_retention_period = 7 db_subnet_group_name = aws_db_subnet_group.rds_subnet_group.name vpc_security_group_ids = [aws_security_group.db_sg.id] skip_final_snapshot = true }
※コードを参照したい場合は、上の[ ▶ コードを展開する ]を選択してください。
デプロイの実施
下記コマンドでAWS環境へデプロイします。
$ terraform init $ terraform plan $ terraform apply
接続確認
踏み台EC2へログインし、SSMパラメータストアを使用し、MySQLへ接続してみます。
$ DB_USER=`aws ssm get-parameters \ --names "/rds/mysql/username" \ --query Parameters[].Value \ --output text \ --region ap-northeast-1` $ DB_PW=`aws ssm get-parameters \ --names "/rds/mysql/password" \ --with-decryption \ --query Parameters[].Value \ --output text \ --region ap-northeast-1` $ mysql -u $DB_USER -p$DB_PW -h myrds.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com
その結果、
[root@ip-10-0-1-227 ~]# mysql -u $DB_USER -p$DB_PW -h myrds.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 78 Server version: 5.7.41-log Source distribution Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]>
無事接続することが出来ました!
終わりに
今回はTerraformでSSMパラメータストアに保管されたパラメータを使用し、RDSを構築してみました。
DBの接続情報を、今回使用したSSMパラメータストアやAWS Secrets Managerに保管することで、
セキュアに接続情報を使用することが可能となります。
この記事がどなたかのお役に立てれば幸いです。